using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using OpenComposite.Base;
using OpenComposite.EII.Designer;
using OpenComposite.Repository.Properties;
using OpenComposite.EII.RepositoryUIs;
using System.Diagnostics;

namespace OpenComposite.EII.Repository
{
	[Designer(typeof(RepositoryItemDesigner))]
	[ToolboxItem(false)]
	[TypeConverter(typeof(ExpandableObjectConverter))]
	public abstract class RepositoryItemBase
		: DataRowItemAbstract, OpenComposite.EII.Repository.IRepositoryItem, IEquatable<IRepositoryItem>,
		IComparable<IRepositoryItem>, IComparable
	{
		#region Initialization
		/// <summary>
		/// Initializes a new instance of the <see cref="RepositoryItemBase"/> class.
		/// </summary>
		/// <param name="IdColName">Name of the ID column.</param>
		/// <param name="NmColName">Name of the name column.</param>
		/// <param name="DescColName">Name of the description column.</param>
		/// <param name="NTextColName">Name of the ntext column.</param>
		/// <param name="NewItemName">New name of the item.</param>
		protected RepositoryItemBase(
			string IdColName, string NmColName, string DescColName, string NTextColName,
			string NewItemName)
		{
			base.id = -1;
			base.name = "";

			base.colnmId = IdColName;
			base.colnmNm = NmColName;
			base.colnmDesc = DescColName;
			base.colnmNText = NTextColName;

			base.sNewItemName = NewItemName;

			SetDefaultValues();
		}

		#endregion

		#region Variables
		private int _changing = 0;
		private bool _isReloading = false;
		private IServiceProvider _serviceProvider;

		#endregion

		#region IRepositoryItem Members

		#region Properties

		/// <summary>
		/// Gets the ID.
		/// </summary>
		/// <value>The ID.</value>
		public int ID
		{
			get { return getInt(colnmId, base.id); }
		}
		/// <summary>
		/// Gets or sets the name.
		/// </summary>
		/// <value>The name.</value>
		public virtual string Name
		{
			get { return getString(colnmNm, base.name); }
			set
			{
				base.name = value;
				setValue("Name", colnmNm, value);
			}
		}
		/// <summary>
		/// Gets or sets the description.
		/// </summary>
		/// <value>The description.</value>
		public virtual string Description
		{
			get { return getString(colnmDesc, ""); }
			set
			{
				if ( this.Description != value ) {
					setValue("Description", colnmDesc, value);
				}
			}
		}
		/// <summary>
		/// Gets or sets the N text.
		/// </summary>
		/// <value>The N text.</value>
		public virtual string NText
		{
			get { return getString(colnmNText, ""); }
			set
			{
				if ( this.NText != value ) {
					setValue("NText", colnmNText, value);
				}
			}
		}

		/// <summary>
		/// Gets the image key.
		/// </summary>
		/// <value>The image key.</value>
		public abstract string ImageKey
		{
			get;
		}
		/// <summary>
		/// Gets the selected image key.
		/// </summary>
		/// <value>The selected image key.</value>
		public abstract string SelectedImageKey
		{
			get;
		}
		/// <summary>
		/// Gets the image.
		/// </summary>
		/// <value>The image.</value>
		public abstract Image Image
		{
			get;
		}
		/// <summary>
		/// Gets the selected image.
		/// </summary>
		/// <value>The selected image.</value>
		public abstract Image SelectedImage
		{
			get;
		}

		/// <summary>
		/// Gets the type of the repository item.
		/// </summary>
		/// <value>The type of the repository item.</value>
		public abstract ItemType RepositoryItemType
		{
			get;
		}
		/// <summary>
		/// Gets the name of the repository item type.
		/// </summary>
		/// <value>The name of the repository item type.</value>
		public abstract string RepositoryItemTypeName
		{
			get;
		}
		/// <summary>
		/// Gets the repository item type description.
		/// </summary>
		/// <value>The repository item type description.</value>
		public abstract string RepositoryItemTypeDescription
		{
			get;
		}

		/// <summary>
		/// Gets the name of the table.
		/// </summary>
		/// <value>The name of the table.</value>
		public abstract string TableName
		{
			get;
		}
		/// <summary>
		/// Gets the name of the ID column.
		/// </summary>
		/// <value>The name of the ID column.</value>
		public virtual string IDColumnName
		{
			get { return colnmId; }
		}

		/// <summary>
		/// Gets a value indicating whether [allow drop].
		/// </summary>
		/// <value><c>true</c> if [allow drop]; otherwise, <c>false</c>.</value>
		public virtual bool AllowDrop
		{
			get { return false; }
		}
		/// <summary>
		/// Gets the allowed child types.
		/// </summary>
		/// <value>The allowed child types.</value>
		public abstract List<ItemType> AllowedChildTypes
		{
			get;
		}

		/// <summary>
		/// Gets the display text.
		/// </summary>
		/// <value>The display text.</value>
		public virtual string Display
		{
			get { return this.Name; }
		}

		/// <summary>
		/// Gets the delete question.
		/// </summary>
		/// <value>The delete question.</value>
		protected virtual string DeleteQuestion
		{
			get { return string.Format(Resources.msgDelete, "'" + this.Display + "'"); }
		}

		#endregion

		#region Events
		/// <summary>
		/// Occurs when the item is changing.
		/// </summary>
		public event OpenComposite.EII.Services.RepositoryChangingEventHandler ItemChanging = null;
		/// <summary>
		/// Occurs when the item was changed.
		/// </summary>
		public event OpenComposite.EII.Services.RepositoryChangedEventHandler ItemChanged = null;

		/// <summary>
		/// Occurs when the item is deleting.
		/// </summary>
		public event OpenComposite.EII.Services.RepositoryEventHandler ItemDeleting = null;
		/// <summary>
		/// Occurs when the item was deleted.
		/// </summary>
		public event OpenComposite.EII.Services.RepositoryEventHandler ItemDeleted = null;
		#endregion

		#region Methods

		/// <summary>
		/// Initializes the service provider.
		/// </summary>
		/// <param name="serviceProvider">The service provider.</param>
		public void InitializeServiceProvider(IServiceProvider serviceProvider)
		{
			_serviceProvider = serviceProvider;
			this.Site = new DesignerSite(serviceProvider, this, null);
		}

		/// <summary>
		/// Sets the ID and name.
		/// </summary>
		/// <param name="id">The ID.</param>
		/// <param name="name">The name.</param>
		public void SetIdAndName(int id, string name)
		{
			base.id = id;
			base.name = name;
			OnItemChanged(this.GetType().GetMethod("SetIdAndName"), null, null);
		}
		/// <summary>
		/// Loads the item with the specified ID.
		/// </summary>
		/// <param name="id">The ID.</param>
		/// <returns></returns>
		public virtual bool Load(int id)
		{
			base.id = id;
			bool isDeleted;
			this.row = Global.Data.SelectRepositoryItem(this.RepositoryItemType, id, out isDeleted);
			return ( this.row != null );
		}
		/// <summary>
		/// Reloads this instance.
		/// </summary>
		/// <returns><c>true</c> if successfully reloaded.</returns>
		[DebuggerStepThrough]
		public override bool Reload()
		{
			if ( !_isReloading ) {
				_isReloading = true;
				try {
					bool isDeleted;
					DataRow rowReloaded = Global.Data.SelectRepositoryItem(this.RepositoryItemType, this.ID, out isDeleted);
					if ( isDeleted )
						//throw new RepositoryItemDeletedException(
						//    string.Format("The {0} \"{1}\" is deleted.", this.RepositoryItemTypeName, rowReloaded[this.colnmNm].ToString()));
						Debug.WriteLine(string.Format("The {0} \"{1}\" is deleted.", this.RepositoryItemTypeName, rowReloaded[this.colnmNm].ToString()));
					else if ( rowReloaded != null )
						this.row = rowReloaded;
					else {
						if ( this.row == null ) {
							this.row = Global.Data.GetNewRepositoryItemDataRow(this.RepositoryItemType);
							this.id = 0;
							this.SetDefaultValues();
						}
					}
				} finally {
					_isReloading = false;
				}
			}
			return ( this.row != null );
		}

		/// <summary>
		/// Saves this instance.
		/// </summary>
		/// <returns></returns>
		public virtual bool Save()
		{
			if ( _changing > 0 ) return false;
			// if ID available but datarow not initialized the load the datarow from the database
			if ( this.ID > 0 && this.row.IsNull(this.colnmId) ) this.Reload();
			DataRow rowNew = null;
			using ( WaitMouse wm = new WaitMouse() ) {
				rowNew = Global.Data.UpdateRepositoryItem(this.RepositoryItemType, row);
			}
			if ( rowNew == null )
				return false;
			else {
				MemberInfo member = this.GetType().GetMethod("Save");
				OnItemChanging(member, null);
				this.row = rowNew;
				using ( WaitMouse wm = new WaitMouse() ) {
					Global.Data.UpdateRepositoryHierarchyDisplay(this);
				}
				OnItemChanged(member, null, this);
				return true;
			}
		}

		/// <summary>
		/// Deletes this instance.
		/// </summary>
		/// <param name="bAsk">if set to <c>true</c> show a message to ask for deleting.</param>
		/// <returns></returns>
		public virtual bool Delete(bool bAsk)
		{
			if ( !bAsk || MessageBox.Show(this.DeleteQuestion, this.RepositoryItemType.ToString(),
				 MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes ) {
				try {
					OnItemDeleting();
				} catch ( Exception ex ) {
					MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
					return false;
				}
				if ( this.ID <= 0 ) {
					OnItemDeleted();
					return true;
				} else {
					RepositoryService repSvc = (RepositoryService)this.GetService(typeof(RepositoryService));
					if ( repSvc == null )
						throw new NullReferenceException("RepositoryService not available.");

					bool bOK = false;
					using ( WaitMouse wm = new WaitMouse() ) {
						bOK = DeleteInternal();
					}
					if ( bOK )
						OnItemDeleted();
					return bOK;
				}
			} else {
				return false;
			}
		}
		/// <summary>
		/// Internal delete the item from the database.
		/// </summary>
		/// <param name="bAsk">if set to <c>true</c> [b ask].</param>
		/// <returns></returns>
		internal virtual bool DeleteFromDBInternal(bool bAsk)
		{
			try {
				OnItemDeleting();
			} catch ( Exception ex ) {
				MessageBox.Show(ex.Message, ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
				return false;
			}
			bool ok = this.Delete(bAsk);
			if ( ok )
				OnItemDeleted();
			return ok;
		}
		/// <summary>
		/// Internally delete the item.
		/// </summary>
		/// <returns></returns>
		internal virtual bool DeleteInternal()
		{
			bool bOK = Global.Data.DeleteRepositoryItem(this.RepositoryItemType, this.ID);
			if ( bOK ) {
				DataTable dt = Global.Data.GetRepositoryHierarchyChildren(this);
				foreach ( DataRow dr in dt.Rows ) {
					IRepositoryItem child = this.RepositoryService.GetItem(
						(ItemType)dr["child_reptype_id"], (int)dr["child_id"], true);
					if ( child != null )
						child.Delete(false);
				}
				bOK = Global.Data.DeleteRepositoryHierarchy(this);
			}
			return bOK;
		}
		/// <summary>
		/// Removes this instance from the db permanently.
		/// </summary>
		/// <param name="bAsk">if set to <c>true</c> ask before deleting.</param>
		/// <returns>
		/// Returns <c>true</c> if destroyed successful; otherwise <c>false</c>.
		/// </returns>
		internal virtual bool Destroy(bool bAsk)
		{
			string message = string.Format("This will delete '{0}' permanently. You will not be able to restore this item.{1}{1}Are you sure?", this.Name, Environment.NewLine);
			string caption = string.Format("Destroy '{0}'", this.Name);

			if ( !bAsk || MessageBox.Show(message, caption, MessageBoxButtons.YesNo, MessageBoxIcon.Information)
							== DialogResult.Yes ) {
				// destroy referenced items or cancel destroying
				CancelEventArgs e = new CancelEventArgs(false);
				OnDestroying(e);

				if ( e.Cancel ) return false;

				// destroy this repository item
				bool destroyed = Global.Data.DeleteRepositoryItem(this.RepositoryItemType, this.ID);

				// successfully destroyed
				if ( destroyed ) OnDestroyed();

				return destroyed;
			} else {
				return false;
			}
		}
		protected virtual void OnDestroying(CancelEventArgs e)
		{
		}
		protected virtual void OnDestroyed()
		{
		}

		/// <summary>
		/// Creates a new item.
		/// </summary>
		/// <returns></returns>
		public virtual bool CreateNew()
		{
			this.row = Global.Data.GetNewRepositoryItemDataRow(this.RepositoryItemType);
			if ( this.row == null ) return false; // EXIT

			this.BeginEdit();
			try {
				this.Name = sNewItemName;
				this.SetDefaultValues();
			} finally {
				this.EndEdit(false);
			}
			return this.Save();
		}

		/// <summary>
		/// Begins the edit.
		/// </summary>
		/// <returns></returns>
		public virtual bool BeginEdit()
		{
			_changing++;
			if ( _changing > 1 )
				return true;
			else if ( row.IsNull(this.IDColumnName) && this.ID > 0 )
				return this.Reload();
			else
				return true;
		}
		/// <summary>
		/// Cancels the edit.
		/// </summary>
		/// <returns></returns>
		public virtual bool CancelEdit()
		{
			_changing--;
			if ( _changing < 0 )
				_changing = 0;
			if ( _changing == 0 )
				return this.Reload();
			else
				return true;
		}
		/// <summary>
		/// Ends the edit.
		/// </summary>
		/// <param name="bSave">if set to <c>true</c> save this instance.</param>
		/// <returns></returns>
		public virtual bool EndEdit(bool bSave)
		{
			bool ok = true;
			_changing--;
			if ( _changing < 0 )
				_changing = 0;
			if ( bSave ) {
				// save item
				ok = this.Save();
			}
			if ( ok && _changing == 0 ) {
				MemberInfo member = this.GetType().GetMethod("EndEdit");
				OnItemChanged(member, null, null);
			}
			return ok;
		}

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <returns></returns>
		public virtual DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew)
		{
			return ShowNewItemForm(idRepository, bAllowContinue, parentItem, ref idDomain,
				out parentItemNew, false, true, true);
		}

		/// <summary>
		/// Shows the new item form.
		/// </summary>
		/// <param name="idRepository">The repository ID.</param>
		/// <param name="bAllowContinue">if set to <c>true</c> to allow save and continue.</param>
		/// <param name="parentItem">The parent item.</param>
		/// <param name="idDomain">The domain ID.</param>
		/// <param name="parentItemNew">The new parent item.</param>
		/// <param name="showAllFolders">if set to <c>true</c> [show all folders].</param>
		/// <param name="showAllDomains">if set to <c>true</c> [show all domains].</param>
		/// <param name="showDisabledDropDownBoxes">if set to <c>true</c> shows folder and domain drop down boxes even if they are set to don't show all items.</param>
		/// <returns></returns>
		protected DialogResult ShowNewItemForm(int idRepository, bool bAllowContinue,
			IRepositoryItem parentItem, ref int idDomain, out IRepositoryItem parentItemNew, bool showAllFolders, bool showAllDomains, bool showDisabledDropDownBoxes)
		{
			FormCreateNewItem dlgNew = new FormCreateNewItem(_serviceProvider, this, bAllowContinue);
			dlgNew.Icon = this.GetIcon();
			dlgNew.DomainID = idDomain;
			dlgNew.ShowAllDomains = showAllDomains;
			if ( !showAllDomains && !showDisabledDropDownBoxes ) {
				dlgNew.DomainsVisible = false;
			}
			dlgNew.ShowAllFolders = showAllFolders;
			if ( !showAllFolders && !showDisabledDropDownBoxes ) {
				dlgNew.FoldersVisible = false;
			}
			if ( !showAllDomains && !showAllFolders && !showDisabledDropDownBoxes ) {
				dlgNew.CreateAtToolStripVisible = false;
			}
			dlgNew.ParentItem = parentItem;
			DialogResult result = dlgNew.ShowDialog();
			if ( result == DialogResult.OK || result == DialogResult.Retry ) {
				idDomain = dlgNew.DomainID;
				parentItemNew = dlgNew.NewParentItem;
			} else {
				idDomain = 0;
				parentItemNew = null;
			}
			return result;
		}

		/// <summary>
		/// Sets the drag drop data object.
		/// </summary>
		/// <param name="dataObj">The data object.</param>
		public virtual void SetDragDropDataObject(IDataObject dataObj)
		{
			dataObj.SetData(this);
		}

		/// <summary>
		/// Gets the icon.
		/// </summary>
		/// <returns></returns>
		public abstract Icon GetIcon();

		/// <summary>
		/// Determines whether the given name is still available in this domain for the type of this item.
		/// </summary>
		/// <param name="newName">The new name.</param>
		/// <returns>
		/// 	<c>true</c> if name is available; otherwise, <c>false</c>.
		/// </returns>
		public bool IsNameAvailable(string newName)
		{
			return Global.Data.RepositoryService.IsItemNameAvailable(this, newName);
		}

		/// <summary>
		/// Copies this instance.
		/// </summary>
		/// <param name="deep"><c>true</c> to recursively copy the item and all subitems;
		/// <c>false</c> to copy only the item itself.</param>
		/// <returns>The copied item.</returns>
		public abstract IRepositoryItem Copy(bool deep);

		#endregion

		#endregion

		#region IServiceProvider Members

		/// <summary>
		/// Gets the service object of the specified type.
		/// </summary>
		/// <param name="serviceType">An object that specifies the type of service object to get.</param>
		/// <returns>
		/// A service object of type <paramref name="serviceType"/>.-or- null if there is no service object of type <paramref name="serviceType"/>.
		/// </returns>
		public object GetService(Type serviceType)
		{
			if ( _serviceProvider != null )
				return _serviceProvider.GetService(serviceType);
			else
				return null;
		}

		#endregion

		#region Public Member

		#region Static
		/// <summary>
		/// Implements the operator ==.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator ==(RepositoryItemBase itemA, RepositoryItemBase itemB)
		{
			if ( itemA is RepositoryItemBase && itemB is RepositoryItemBase )
				return ( itemA.RepositoryItemType == itemB.RepositoryItemType && itemA.ID == itemB.ID );
			else
				return ( (object)itemA == (object)itemB );
		}
		/// <summary>
		/// Implements the operator ==.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator ==(IRepositoryItem itemA, RepositoryItemBase itemB)
		{
			if ( itemA is IRepositoryItem && itemB is RepositoryItemBase )
				return ( itemA.RepositoryItemType == itemB.RepositoryItemType && itemA.ID == itemB.ID );
			else
				return ( (object)itemA == (object)itemB );
		}
		/// <summary>
		/// Implements the operator ==.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator ==(RepositoryItemBase itemA, IRepositoryItem itemB)
		{
			if ( itemA is RepositoryItemBase && itemB is IRepositoryItem )
				return ( itemA.RepositoryItemType == itemB.RepositoryItemType && itemA.ID == itemB.ID );
			else
				return ( (object)itemA == (object)itemB );
		}
		/// <summary>
		/// Implements the operator !=.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator !=(RepositoryItemBase itemA, RepositoryItemBase itemB)
		{
			if ( itemA is RepositoryItemBase && itemB is RepositoryItemBase )
				return ( itemA.RepositoryItemType != itemB.RepositoryItemType || itemA.ID != itemB.ID );
			else
				return ( (object)itemA != (object)itemB );
		}
		/// <summary>
		/// Implements the operator !=.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator !=(IRepositoryItem itemA, RepositoryItemBase itemB)
		{
			if ( itemA is IRepositoryItem && itemB is RepositoryItemBase )
				return ( itemA.RepositoryItemType != itemB.RepositoryItemType || itemA.ID != itemB.ID );
			else
				return ( (object)itemA != (object)itemB );
		}
		/// <summary>
		/// Implements the operator !=.
		/// </summary>
		/// <param name="itemA">The item A.</param>
		/// <param name="itemB">The item B.</param>
		/// <returns>The result of the operator.</returns>
		public static bool operator !=(RepositoryItemBase itemA, IRepositoryItem itemB)
		{
			if ( itemA is RepositoryItemBase && itemB is IRepositoryItem )
				return ( itemA.RepositoryItemType != itemB.RepositoryItemType || itemA.ID != itemB.ID );
			else
				return ( (object)itemA != (object)itemB );
		}
		/// <summary>
		/// Compares two repository base items by the name.
		/// </summary>
		/// <param name="a">The first item.</param>
		/// <param name="b">The second item.</param>
		/// A 32-bit signed integer that indicates the relative order of the <see cref="T:RepositoryItemBase"/> name being compared. 
		/// The return value has the following meanings: 
		/// Value Meaning Less than zero the <paramref name="a"/> parameter is less than the <paramref name="b"/> parameter.
		/// Zero the <paramref name="a"/> is equal to <paramref name="b"/>. 
		/// Greater than zero the <paramref name="a"/> is greater than <paramref name="b"/>.
		public static int CompareByName(RepositoryItemBase a, RepositoryItemBase b)
		{
			return string.Compare(a.Name, b.Name);
		}
		#endregion

		#region Methods
		/// <summary>
		/// Returns a <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
		/// </summary>
		/// <returns>
		/// A <see cref="T:System.String"/> that represents the current <see cref="T:System.Object"/>.
		/// </returns>
		public override string ToString()
		{
			//return string.Format("{0} ({1})", this.Display, this.ID);
			return this.Display;
		}

		/// <summary>
		/// Determines whether the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>.
		/// </summary>
		/// <param name="obj">The <see cref="T:System.Object"/> to compare with the current <see cref="T:System.Object"/>.</param>
		/// <returns>
		/// true if the specified <see cref="T:System.Object"/> is equal to the current <see cref="T:System.Object"/>; otherwise, false.
		/// </returns>
		/// <exception cref="T:System.NullReferenceException">The <paramref name="obj"/> parameter is null.</exception>
		public override bool Equals(object obj)
		{
			RepositoryItemBase item = obj as RepositoryItemBase;
			if ( item != null ) {
				return ( this.RepositoryItemType == item.RepositoryItemType && this.ID == item.ID );
			} else {
				return false;
			}
		}
		/// <summary>
		/// Serves as a hash function for a particular type.
		/// </summary>
		/// <returns>
		/// A hash code for the current <see cref="T:System.Object"/>.
		/// </returns>
		public override int GetHashCode()
		{
			return unchecked(( (int)this.RepositoryItemType ) + ( this.ID * 100 ));
		}

		#endregion

		#endregion

		#region Protected Members

		#region Properties

		/// <summary>
		/// Gets the repository service.
		/// </summary>
		/// <value>The repository service.</value>
		protected virtual RepositoryService RepositoryService
		{
			get
			{
				return (RepositoryService)this.GetService(typeof(RepositoryService));
			}
		}

		#endregion

		#region Methods

		/// <summary>
		/// Called when item changing.
		/// </summary>
		/// <param name="member">The changing member.</param>
		protected override bool OnItemChanging(MemberInfo member, object newValue)
		{
			// don't fire event if change started with BeginEdit
			//if ( _changing > 0 )
			//    return true;

			Services.RepositoryChangingEventHandler tmp = this.ItemChanging;
			if ( tmp != null ) {
				Services.RepositoryChangingEventArgs e = new OpenComposite.EII.Services.RepositoryChangingEventArgs(this, member, newValue);
				tmp(this, e);
				return !e.Cancel;
			}
			return true;
		}
		/// <summary>
		/// Called when item changed.
		/// </summary>
		/// <param name="member">The changed member.</param>
		/// <param name="oldValue">The old value.</param>
		/// <param name="newValue">The new value.</param>
		protected override void OnItemChanged(MemberInfo member, object oldValue, object newValue)
		{
			// don't fire event if change started with BeginEdit
			if ( _changing > 0 )
				return;

			Services.RepositoryChangedEventHandler tmp = this.ItemChanged;
			if ( tmp != null ) {
				tmp(this, new OpenComposite.EII.Services.RepositoryChangedEventArgs(this, member, oldValue, newValue));
			}
		}
		/// <summary>
		/// Called when [item deleting].
		/// </summary>
		protected virtual void OnItemDeleting()
		{
			Services.RepositoryEventHandler tmp = this.ItemDeleting;
			if ( tmp != null ) {
				tmp(this, new OpenComposite.EII.Services.RepositoryEventArgs(this));
			}
		}
		/// <summary>
		/// Called when [item deleted].
		/// </summary>
		protected virtual void OnItemDeleted()
		{
			Services.RepositoryEventHandler tmp = this.ItemDeleted;
			if ( tmp != null ) {
				tmp(this, new OpenComposite.EII.Services.RepositoryEventArgs(this));
			}
		}

		/// <summary>
		/// Sets the default values.
		/// </summary>
		protected virtual void SetDefaultValues()
		{
			return;
		}

		/// <summary>
		/// Copies the data row of this instance to target item.
		/// </summary>
		/// <param name="targetItem">The target item.</param>
		protected void CopyDataRowToTarget(RepositoryItemBase targetItem)
		{
			this.CopyDataRowToTarget(targetItem, true);
		}
		protected void CopyDataRowToTarget(RepositoryItemBase targetItem, bool createCopyOfName)
		{
			if ( targetItem.row == null ) {
				targetItem.row = this.row.Table.NewRow();
			}
			foreach ( DataColumn col in this.row.Table.Columns ) {
				if ( col.ColumnName == colnmId ) {
					if ( targetItem.row[col.ColumnName] == this.row[col.ColumnName] ) {
						targetItem.row[col.ColumnName] = -1;
					}
				} else if ( col.ColumnName == colnmNm && createCopyOfName ) {
					string nm = "CopyOf_" + this.row[col.ColumnName];
					bool tryOtherName = false;
					int counter = 2;
					do {
						tryOtherName = false;
						DataTable dt = Global.Data.SearchRepositoryItems(
							Global.Status.CurrentDomainId, targetItem.RepositoryItemType,
							nm, null, true);
						if ( dt != null && dt.Rows.Count > 0 ) {
							tryOtherName = true;
							nm = String.Format("Copy{0}Of_{1}", counter, this.row[col.ColumnName]);
							counter++;
						}
					} while ( tryOtherName );
					targetItem.row[col.ColumnName] = nm;
				} else {
					targetItem.row[col.ColumnName] = this.row[col.ColumnName];
				}
			}
			targetItem.Save();
		}

		#endregion

		#endregion

		#region IComponent Members

		/// <summary>
		/// Represents the method that handles the <see cref="E:System.ComponentModel.IComponent.Disposed"/> event of a component.
		/// </summary>
		public event EventHandler Disposed = null;

		private ISite _site = null;
		/// <summary>
		/// Gets or sets the <see cref="T:System.ComponentModel.ISite"/> associated with the <see cref="T:System.ComponentModel.IComponent"/>.
		/// </summary>
		/// <value></value>
		/// <returns>The <see cref="T:System.ComponentModel.ISite"/> object associated with the component; or null, if the component does not have a site.</returns>
		public ISite Site
		{
			get
			{
				return _site;
			}
			set
			{
				_site = value;
			}
		}

		#endregion

		#region IDisposable Members

		/// <summary>
		/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
		/// </summary>
		public void Dispose()
		{
			try {
				this.row = null;
			} catch { }
			try {
				EventHandler tmp = this.Disposed;
				if ( tmp != null ) {
					tmp(this, EventArgs.Empty);
				}
			} catch {
			}
		}

		#endregion

		#region IEquatable<IRepositoryItem> Members

		/// <summary>
		/// Indicates whether the current object is equal to another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// true if the current object is equal to the <paramref name="other"/> parameter; otherwise, false.
		/// </returns>
		public bool Equals(IRepositoryItem other)
		{
			return ( other != null && this.RepositoryItemType == other.RepositoryItemType && this.ID == other.ID );
		}

		#endregion

		#region IComparable<IRepositoryItem> Members

		/// <summary>
		/// Compares the current object with another object of the same type.
		/// </summary>
		/// <param name="other">An object to compare with this object.</param>
		/// <returns>
		/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has the following meanings: Value Meaning Less than zero This object is less than the <paramref name="other"/> parameter.Zero This object is equal to <paramref name="other"/>. Greater than zero This object is greater than <paramref name="other"/>.
		/// </returns>
		public int CompareTo(IRepositoryItem other)
		{
			if ( this.RepositoryItemType != other.RepositoryItemType ) {
				return this.RepositoryItemType.CompareTo(other.RepositoryItemType);
			} else {
				return this.ID.CompareTo(other.ID);
			}
		}

		#endregion

		#region IComparable Members

		/// <summary>
		/// Compares the current instance with another object of the same type.
		/// </summary>
		/// <param name="obj">An object to compare with this instance.</param>
		/// <returns>
		/// A 32-bit signed integer that indicates the relative order of the objects being compared. The return value has these meanings: Value Meaning Less than zero This instance is less than <paramref name="obj"/>. Zero This instance is equal to <paramref name="obj"/>. Greater than zero This instance is greater than <paramref name="obj"/>.
		/// </returns>
		/// <exception cref="T:System.ArgumentException">
		/// 	<paramref name="obj"/> is not the same type as this instance. </exception>
		public int CompareTo(object obj)
		{
			IRepositoryItem other = obj as IRepositoryItem;
			if ( other == null ) return -1;
			return this.CompareTo(other);
		}

		#endregion
	}

	#region Class: RepositoryItemDragDropContainer
	public class RepositoryItemDragDropContainer
	{
		public RepositoryItemDragDropContainer(RepositoryItemBase item, bool bCreateDesignerControl)
		{
			_item = item;
			_bCreateDesignerControl = bCreateDesignerControl;
		}
		private readonly RepositoryItemBase _item;
		public RepositoryItemBase Item
		{
			get { return _item; }
		}

		private readonly bool _bCreateDesignerControl;
		public bool CreateDesignerControl
		{
			get { return _bCreateDesignerControl; }
		}


	}
	#endregion

	#region Class: RepositoryItemChangedEventArgs : Base: EventArgs
	public class RepositoryItemChangedEventArgs : EventArgs
	{
		public RepositoryItemChangedEventArgs(string changedPropertyName, bool isDeleted)
		{
			_changedPropNm = changedPropertyName;
			_isDeleted = isDeleted;
		}
		private readonly string _changedPropNm;
		public string ChangedMembers
		{
			get { return _changedPropNm; }
		}
		private readonly bool _isDeleted;
		public bool IsDeleted
		{
			get { return _isDeleted; }
		}

	}
	#endregion

	#region Class: RepositoryItemAttribute
	[global::System.AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
	internal sealed class RepositoryItemAttribute : Attribute
	{
		// See the attribute guidelines at 
		//  http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconusingattributeclasses.asp
		private readonly ItemType _itemType;
		private readonly string _tableName;
		private readonly string _idColumnName;

		public RepositoryItemAttribute(ItemType itemtype, string tableName, string idColumnName)
		{
			this._itemType = itemtype;
			this._tableName = tableName;
			this._idColumnName = idColumnName;
		}
		public ItemType ItemType
		{
			get
			{
				return this._itemType;
			}
		}
		public string TableName
		{
			get
			{
				return this._tableName;
			}
		}
		public string IdColumnName
		{
			get
			{
				return this._idColumnName;
			}
		}
	}

	#endregion
}
